import { createAsyncThunk, createSlice, isRejected } from "@reduxjs/toolkit";
import { AnalyzeResult } from "./Analyze";
import { request } from "../util/Net";
import { RootState } from "./store";
import { isExceptionAction } from "./util";

// 1. Data structure and combinations.

/**
 * Describe information of each select history.
 */
interface SelectHistoryEntry {
  /**
   * ID of the select history entry, must be unique and auto-increment.
   */
  id: number;
  /**
   * Select time, must be in ISO format.
   * Format: YYYY-MM-DDTHH:mm:ss.sss
   */
  time: string;
  /**
   * Hash of the image.
   */
  hash: string;
  /**
   * Result of the analysis.
   */
  result: AnalyzeResult
};

interface SelectHistoryDetail {
  id: number;
  time: string;
  hash: string;
  result: AnalyzeResult;
  data: string;
}

// 2. Requests and Responses, for communication with backend.

// 2.1 Requests.

/**
 * Request to fetch all select history.
 * @path /service/history/fetchAll
 */
type FetchAllSelectHistoryRequest = null;

interface FetchSelectHistoryRequest {
  id: number;
};

// 2.2 Responses.

/**
 * Response for fetch all select history;
 * @path /service/history/fetchAll
 */
type FetchAllSelectHistoryResponse = SelectHistoryEntry[];

interface FetchSelectHistoryResponse {
  detail: SelectHistoryDetail;
};

// 3. Params for reducers.

interface FetchSelectHistoryParams {
  id: number;
  download: boolean;
};

// 4. State and initial value definition.

/**
 * Redux state repository for this slice.
 */
interface SelectHistoryState {
  loaded: boolean;
  entries: SelectHistoryEntry[];
  detailLoaded: boolean;
  detail: SelectHistoryDetail | undefined;
  download: boolean;
};

/**
 * Initial state of this slice.
 */
const initialState: SelectHistoryState = {
  loaded: false,
  entries: [],
  detailLoaded: false,
  detail: undefined,
  download: false
};

// 5. Async functions definition.

const fetchAllSelectHistory = createAsyncThunk('api/fetchAllSelectHistory', async () => {
  const response = await request<FetchAllSelectHistoryResponse, FetchAllSelectHistoryRequest>('/service/history/fetchAll');
  return response.data;
});

const fetchSelectHistoryDetail = createAsyncThunk('api/fetchSelectHistoryDetail', async (params: FetchSelectHistoryParams) => {
  const response = await request<FetchSelectHistoryResponse, FetchSelectHistoryRequest>('/service/history/detail', {
    id: params.id
  });
  return response.data;
})

// 6. Slice definition.

/**
 * Slice of the module Analyze.
 */
const selectHistorySlice = createSlice({
  name: 'selectHistory',
  initialState: initialState,
  reducers: {
    clear: (state) => {
      state.loaded = false;
      state.detailLoaded = false;
    },
    clearDetail: (state) => {
      state.detailLoaded = false;
      state.download = false;
    }
  },
  extraReducers: (builder) => {
    builder.addCase(fetchAllSelectHistory.fulfilled, (state, action) => {
      if (action.payload.code === 0) {
        state.loaded = true;
        state.entries = action.payload.result;
      }
    }).addCase(fetchSelectHistoryDetail.fulfilled, (state, action) => {
      if (action.payload.code === 0) {
        state.detail = action.payload.result.detail;
        if (action.meta.arg.download) {
          state.download = true;
        }
        else {
          state.detailLoaded = true;
        }
      }
    }).addMatcher(isExceptionAction, (state, action) => {
      
      console.error(action.payload);
    }).addMatcher(isRejected, (state, action) => {
      
    });
  }
});

// 7. Selectors for state in this module.

export const selectHistoryEntriesLoaded = (state: RootState) => state.SelectHistory.loaded;
export const selectHistoryEntries = (state: RootState) => state.SelectHistory.entries;
export const selectHistoryDetailLoaded = (state: RootState) => state.SelectHistory.detailLoaded;
export const selectHistoryDetail = (state: RootState) => state.SelectHistory.detail;
export const selectHistoryDownload = (state: RootState) => state.SelectHistory.download;

// 8. Export necessary modules.

export default selectHistorySlice.reducer;
export type { SelectHistoryEntry, SelectHistoryDetail };
export { fetchAllSelectHistory, fetchSelectHistoryDetail };
export const selectHistoryActions = selectHistorySlice.actions;
